iT邦幫忙

0

筆記|React - 番外 - React 如何控制 <input />

Kim 2023-02-25 13:17:44685 瀏覽
  • 分享至 

  • xImage
  •  

☁️ 背景脈絡

會想整理這篇筆記是因為在這篇官方文件的 Challenge 1 的程式碼遇到自己和同學當下都難以解釋的現象
(以下會簡單解釋,但先觀看上方 challenge 內容再看會比較好理解):

已知觸發 Last name <input /> 會讓 player 物件只留下 lastName 的屬性,所以其他因 player 所生的畫面會消失,像是 score <label> 確實地消失了,但... First name <input /> 你怎麼還在???這時留意到 console 跳出了關鍵的提示 Warning: A component is changing a controlled input to be uncontrolled 於是就開始挖坑了...

⬇️ 原本的程式碼

原本的程式碼

⬇️ 觸發 Last name

觸發 Last name


📝 主題筆記

一、瀏覽器本身就會對 HTML <input /> 所做的事

  • 當只有放 <input />,使用者輸入文字瀏覽器會

    1. 自動更新 input 裡面的文字
    2. 觸發 onChange 事件(說明 input 有被更新)

    HTML

  • 當我們在 <input /> 裡面擺入 value 屬性,input 裡會出現 value 設定的值,且因為是寫死的值,所以無法改動
    加入 value attribute

    這時新增 value 的瞬間也會噴 Warning ,但留意內容是寫「從 uncontrolled 變 controlled」(後面再談)

二、React 如何接管控制 <input />

  • 以下使用 useState 來接管控制 <input /> (留意圖中紫色的字為瀏覽器本身就會做的事
    0. 打完畫面中的程式碼之後,右邊畫面的 input 一開始是呈現空字串
    1. 使用者輸入'8'
    2. 瀏覽器更新 input 裡面的文字,畫面出現'8'
    3. 瀏覽器觸發 onChange 事件(說明 input 有被更新)
    4. onChange 被觸發後進而觸發 handleChange 函式
    5. handleChange 裡的 setText 把 input 被更新的 value 更新到 text 變數,並且觸發 re-render
    6. 在 re-render 後,這時的 text='8',於是現在畫面上的'8'是從 value={text} 置入的,和當初使用者輸入進去的有差

React 如何接管控制

筆者在理解這一切步驟之後覺得實在太有趣了!(∂ω∂)

三、 React 從瀏覽器接管控制有什麼好處?

比較一下 React 介入前後的程式碼,會思考同樣的畫面呈現,何必要寫成 React 這樣這麼多的程式碼?
當然是有好處的!

1. 如果我們要取使用者輸入在 input 的值

Before: document.querySelector('.user-input').value
After: text

2. 如果我們要更新 input 的 value

Before: document.querySelector('.user-input').value = '更新的值'
After: setText('更新的值')

3. 每當使用者輸入,元件會觸發 re-render

如此一來可以設計許多進階的功能,比如我們如果希望使用者在輸入的同時,畫面某處也會即時顯示他的輸入內容,就能輕易做到!不用再手動取值,然後更改 DOM 諸如此類...
進階功能一


↩️ 回歸開頭所遇到的 Warning

在理解瀏覽器本身就會對 <input /> 做些處理,以及也能設計 React 去擁有控制權之後,接著來看React 官方文件 - input,可以知道 <input> 這個元件本身是 uncontrolled 的,但可以透過設定 value、checked 屬性(後者是 for checkbox input or radio button),來讓它變成 controlled 的狀態。而在設定成 controlled 的狀態後,就必須設定 onChange handler 來更新 value(不然 value 會固定住)

.

接著官方文件提到了很多點注意事項,為了專注於 Warning,這裡只點出三點:

  1. An input can’t be both controlled and uncontrolled at the same time.
  2. An input cannot switch between being controlled or uncontrolled over its lifetime.
  3. 如果要 control input,放進去 value 的值不可以是 undefinednull,若希望初始值是空的,就擺入空字串'',不然還是會被視為 uncontrolled

.

有了以上背景知識就可以來討論遇到的 Warning 了!

在 challenge 的情境,原本 player.firstName 是有值的,一旦觸發 Last name <input /> 讓 player 物件只留下 lastName 的屬性,所以 First name <input /> 的 value={player.firstName} 變為 undefined,這讓First name <input />瞬間變成 uncontrolled 的元件,於是就噴了 Warning。這時 First name <input /> 是在 uncontrolled 的狀態下保持了原本輸入在 input 框框中的內容,也就是為何裡面的值還在的原因

⬇️ 此處是 controlled 變 uncontrolled

觸發 Last name

.

在「筆記一」的情境,是由於原本 <input /> 沒有寫 value 屬性來控制,加入value="你改不了我~~"的瞬間,就如同文件所說,變成 controlled 元件,會噴 Warning 是因為違反了上面第二點注意事項,它在這個 lifttime 從 uncontrolled 變 controlled

⬇️ 此處是 uncontrolled 變 controlled,重新刷頁面 Warning 就會消失

加入 value attribute

.

同場加映(?)
測試注意事項第三點,設定 useState(undefined),在使用者輸入值觸發一切連環效應後...

⬇️ 果真是從 uncontrolled 變 controlled !

測試注意事項第三點


🙏🏻 其他參考資料

Modern React with Redux [2023 Update] - Handling Input Element


以上,有任何想法或文內有誤、不清楚歡迎提出,謝謝大家 🙏🏻
.
Special thanks to 一起討論的同學和助教!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言